iT邦幫忙

2024 iThome 鐵人賽

DAY 25
1

簡單介紹完所有會用到的東西跟概念之後,接著要切入實做的層面,來看看是如何使用Opentelemetry SDK來產生遙測資料,那我今天會以官方提供的python code做介紹。

產生遙測資料

Traces

建立 TracerProvider

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor,
    ConsoleSpanExporter,
)

provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)

# Sets the global default tracer provider
trace.set_tracer_provider(provider)

# Creates a tracer from the global tracer provider
tracer = trace.get_tracer("my.tracer.name")

建立span

def do_work():
    with tracer.start_as_current_span("span-name") as span:
        # do some work that 'span' will track
        print("doing some work...")
        # When the 'with' block goes out of scope, 'span' is closed for you

current_span = trace.get_current_span()

current_span.set_attribute("operation.value", 1)
current_span.set_attribute("operation.name", "Saying hello!")
current_span.set_attribute("operation.other-stuff", [1, 2, 3])

Adding links(手動將兩個span串起一起)

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("span-1"):
    # Do something that 'span-1' tracks.
    ctx = trace.get_current_span().get_span_context()
    link_from_span_1 = trace.Link(ctx)

with tracer.start_as_current_span("span-2", links=[link_from_span_1]):
    # Do something that 'span-2' tracks.
    # The link in 'span-2' is causally associated it with the 'span-1',
    # but it is not a child span.
    pass

Metrics

# These are the necessary import declarations
from opentelemetry import trace
from opentelemetry import metrics

from random import randint
from flask import Flask, request
import logging

# Acquire a tracer
tracer = trace.get_tracer("diceroller.tracer")
# Acquire a meter.
meter = metrics.get_meter("diceroller.meter")

# Now create a counter instrument to make measurements with
roll_counter = meter.create_counter(
    "dice.rolls",
    description="The number of rolls by roll value",
)

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@app.route("/rolldice")
def roll_dice():
    # This creates a new span that's the child of the current one
    with tracer.start_as_current_span("roll") as roll_span:
        player = request.args.get('player', default = None, type = str)
        result = str(roll())
        roll_span.set_attribute("roll.value", result)
        # This adds 1 to the counter for the given roll value
        roll_counter.add(1, {"roll.value": result})
        if player:
            logger.warn("{} is rolling the dice: {}", player, result)
        else:
            logger.warn("Anonymous player is rolling the dice: %s", result)
        return result

def roll():
    return randint(1, 6)

Instrumentation

上述就是建立tracer、meter的實例去負責產生span、metrics,如果清楚要追蹤哪一段程式碼的行動,可以自己像上述一樣定義Span的範圍。

如果換個狀況是,你像我一樣不清楚應該要追蹤哪一段,又或者我想對某一個套件的所有動作進行紀錄,最好可以自動去偵測我微服務的整個範圍,並且自動產生Span,我不想要一個一個加入Span。這個時候有個神兵利器就出現了,那就是「Instrumentation」

我可以使用 instrumentation-libraries針對特定的instrumentation套件偵測

pip install opentelemetry-instrumentation-{instrumented-library}
pip install -e ./instrumentation/opentelemetry-instrumentation-{integration}
pip install opentelemetry-instrumentation-httpx

以httpx為例:

import httpx
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor

url = "https://some.url/get"
HTTPXClientInstrumentor().instrument()

with httpx.Client() as client:
     response = client.get(url)

async with httpx.AsyncClient() as client:
     response = await client.get(url)

但是這樣還是要修改程式碼,如果今天我是一個維運的角色,我必須得要trace,但是我不能動到程式碼,那我也可以自動偵測該微服務所使用的套件,一樣透過安裝Instrumentation套件,opentelemetry-bootstrap -a install讓他偵測微服務所使用到的套件並安裝,最後直接用opentelemetry-instrument啟動微服務就可以了

pip install opentelemetry-distro
opentelemetry-bootstrap -a install
export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
opentelemetry-instrument \
    --traces_exporter console \
    --metrics_exporter console \
    --logs_exporter console \
    --service_name dice-server \
    flask run -p 8080

霹靂啪拉講了一堆,其實今天重點不在於程式碼。我想給跟我一樣是入門可觀測性的夥伴說,我自己的心得是,當你可以修改微服務的程式碼的時候,很多事情SDK都可以解決。但是今天如果你的角色,沒辦法修改微服務的程式碼的時候,你就只能透過其他的方式,讓Span去串起來,甚至現在能看到的範例,都還是以網頁框架flask舉例。

上述都是基於在同個且同類型微服務的情況下,所以我今天遇到的挑戰就是,如果今天是不同個微服務,不同個且不同種的微服務情況下又該怎麼解決。比如說現在常見的串流資料方式,透過mqtt協定來傳輸資料,從mqtt broker 到 confluent kafka 再到 後端,完全不知道在mqtt怎麼inject、extract,而且有些現成的解決方案,東西安裝好設定好就能用,我根本不會改到程式碼,所以也沒機會inject、extract,所以我也不知道怎麼讓這個流程的Span組成完整的Trace。

只能說頭好痛,超級麻煩/images/emoticon/emoticon02.gif

不過我相信One Piece只是放在這廣大的世界裡的一角,不是我找不到,只是我還沒找到。/images/emoticon/emoticon28.gif

今日小總結,產生遙測資料的方式有三種

  • 修改程式碼 with tracer.start_as_current_span (侵入式)
  • 修改程式碼加入微服務中使用到套件的Instrumentor Instrumentor().instrument() (半侵入式)
  • 不修改程式碼 (非侵入式)

另外小補充,曾經有問過某個大大相關的問題,那我也得到一個警示就是,雖然不用動到程式碼,但是可能會有效能上的問題。

參考資料

Opentelemetry python libraries
Opentelemetry instrumentation
Opentelemetry Python zero-code instrumentation


上一篇
第二十四篇:Opentelemetry Collector
下一篇
第二十六篇:上下文傳播 How to do
系列文
成為 Kubernetes 特級咒術師的 30 天修行26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言